#!/usr/bin/env python
import sys
import antlr3
from parsing.GencfaLexer import GencfaLexer
from parsing.GencfaParser import GencfaParser

from graph.Genedge import Genedge
from graph.GenGraph import GenGraph
from io.GenInput import GenInput
from io.GenOutput import GenOutput
from evo.Mutator import Mutator
from evo.Combinator import Combinator
from ConfigParser import ConfigParser
from io.Parser import parse

from GencfaShell import GencfaShell
from Pastor import Pastor

import os
import subprocess
import random
import copy
import logging
import logging.handlers
 
print "GENCFA embryo_3 (basic recombination)"

LOG_FILENAME = 'main.log'
# Set up a specific logger with our desired output level
logger = logging.getLogger('main')
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(LOG_FILENAME, maxBytes=200000, backupCount=5)
logger.addHandler(handler)


cfg_parser = ConfigParser() # start up the parser for configuration parameters
cfg_parser.read("params.properties") # read the params.properties file   
mutator = Mutator(cfg_parser.get("params", "all").split('#')) #start the Mutator with available parameters (cfdg parameters, e.g. hue, sat, etc.)
combinator = Combinator()
spitter = GenOutput() # create the grammar spitter

cfg_parser.read("config.properties")    # read the config.properties file
working_dir = cfg_parser.get("paths", "working_dir")    # get working directories
output_n = int(cfg_parser.get("params", "childs"))  # get number of childs to output

parent_a_file = cfg_parser.get("parents", "parent_a")   # get the source for parent A
parent_b_file = cfg_parser.get("parents", "parent_b")   # get the source for parent B
parent_c_file = cfg_parser.get("parents", "parent_c")   # get the source for parent C
parent_d_file = cfg_parser.get("parents", "parent_d")   # get the source for parent D

grapho_a = parse(parent_a_file)   # build parent A
grapho_a.set_name("0#1")
logger.debug("0#1:\n")
logger.debug(grapho_a.print_graph())

grapho_b = parse(parent_b_file)   # build parent B
grapho_b.set_name("0#2")
logger.debug("0#2:\n")
logger.debug(grapho_b.print_graph())

grapho_c = parse(parent_c_file)   # build parent C
grapho_c.set_name("0#3")
logger.debug("0#3:\n")
logger.debug(grapho_c.print_graph())

grapho_d = parse(parent_d_file)   # build parent D
grapho_d.set_name("0#4")
logger.debug("0#4:\n")
logger.debug(grapho_d.print_graph())

pastor = Pastor(mutator) # initiate Pastor
pastor.add_individual(grapho_a)   # build initial pop
pastor.add_individual(grapho_b)
pastor.add_individual(grapho_c)
pastor.add_individual(grapho_d)

pastor.init()
gen_number = 0

shell = GencfaShell(pastor, spitter)

shell.cmdloop()
"""

while(True):
    gen_number += 1
    pastor.eval_pop()
    pastor.build_offspring()
    ind_number = 0
    for individual in pastor.offspring:
        ind_number += 1
        name = "GEN" + str(gen_number) + "#" + str(ind_number)
        logger.debug("SPITTING INDIVIDUAL: " + str(individual.name()))
        spitter.spit_grammar(individual, name + ".cfdg")
    
    pastor.next_gen()
    


for i in range(output_n):
    
    grapho_t = copy.deepcopy(grapho)
    try:
        nature(grapho_t, mutator)
    
        file = str(i) + ".cfdg"
        spitter.spit_grammar(grapho_t, file) #spits back the graph as CFA grammar
    
    
        #subprocess.call(["./cfdg", working_dir + file, file + ".png"])
    except:
        pass

"""

def nature(graph, mutator):
    if mutator.roulette(20):
        mutator.mutate_duplicate_node(grapho)
    
    if mutator.roulette(20):
        mutator.mutate_remove_node(grapho)
    
    if mutator.roulette(5):
        mutator.mutate_startshape(grapho)
    
    for node in grapho.nodes_iter():
        if mutator.roulette(3):
            mutator.mutate_add_edge(grapho, node)
        
        if mutator.roulette(5):
            mutator.mutate_remove_edge(grapho, node)
        
        for instance in grapho[node].instance_list():
            for edge in grapho[node][instance]:
                
                if mutator.roulette(1):
                    mutator.mutate_change_param(edge)
                    
                if mutator.roulette(1):
                    mutator.mutate_remove_param(edge)
                
                if mutator.roulette(1):
                    mutator.mutate_add_param(edge)

def build_graph(input_file):
    """
    builds a graph given an input grammar file
    """
    print("\nBUILD_GRAPH. building graph for " + str(input_file))
    
    file = open(input_file)
    parser = GenInput(file) #Creates the parser object
    parser.parse() #Parsing done. Retrieve symbol table
    file.close()
    
    grapho = GenGraph() #Creates graph object
    grapho.set_startshape(parser.startshape)
    grapho.set_background(parser.background)
    current_node = ""
    for instance_name in parser.symbol_table.iterkeys():   
        splited_instance = instance_name.split('#')
        node = splited_instance[0]
        if node != current_node:
            current_node = node   
        invocations = parser.symbol_table[instance_name] 
        for invoc in invocations:
            edge = Genedge(invoc[:-1]) #creates edge object with adjustments as payload
            grapho.add_edge(current_node, invoc[-1], edge, splited_instance[1]) #origin, destination, payload, instance
        #end for
    #end for
    del parser
    return grapho 
